Skip to content

feat: complex playground — explore complex functions f(z) on any image#14

Merged
silviot merged 3 commits into
mainfrom
feat/complex-playground
Jun 2, 2026
Merged

feat: complex playground — explore complex functions f(z) on any image#14
silviot merged 3 commits into
mainfrom
feat/complex-playground

Conversation

@silviot

@silviot silviot commented May 31, 2026

Copy link
Copy Markdown
Collaborator

Summary

A new complex playground view (5th tool-rail button, the graph glyph) that warps the loaded image — a gallery picture, the bundled sample, or the generated grid/polar patterns — through a chosen complex function f(z), GeoGebra-style. Built from a shaping session (shaping/complex-playground-shaping.md).

Feature (feat(playground))

  • 12 presets, one GLSL branch each in a WebGL2 uber-shader, mirrored on CPU for the no-WebGL2 fallback: identity, , zⁿ, 1/z, Möbius k(z−z₀)/(z−z∞), Joukowski, exp, log, Escher zᵃ, sin, tan, sin(1/z). Each carries an analytic f' for mip-LOD anti-aliasing.
  • Live, schema-generated controls (sliders / complex number-fields) + reset; the active formula renders live and updates as you tweak.
  • Hand-drag adds a complex constant c to the formula, with a toggle for domain f(z+c) vs output f(z)+c; wheel zooms.
  • Draggable on-canvas handles for a preset's zero/pole (Möbius), plus an origin cross and unit-circle overlay.
  • Fill modes (tile / clamp / mirror) so out-of-image samples never go black.

It runs on its own complex frame (origin + scale), independent of the Droste doc.rect; it only borrows doc.image and the existing image-source paths (DropZone sample/patterns, Gallery).

New files: src/lib/render/playground/{presets.ts,shader.frag.glsl,gl.ts,cpu.ts}, src/lib/ui1/playground.svelte.ts, src/components/ui1/{PlaygroundStage,PlaygroundControls}.svelte, tests/render/playground-presets.test.ts. Wired into state.svelte.ts (ViewMode), ToolRail.svelte, UiVariant1.svelte, icons.ts.

Test Coverage

tests/render/playground-presets.test.ts — 22 tests covering preset f(z) values, the Möbius f' sign, uniform packing, and live-formula text in both pan modes. Suite: 22 → 44 tests total, all passing.

Coverage is on the pure preset library (the math). The Svelte components and GL/CPU renderers are verified by live browser QA below (the .svelte.ts state + GLSL can't run under node/vitest).

Pre-Landing Review

Inline checklist pass: no SQL/data/LLM trust-boundary surface; no secrets; resource cleanups present (dispose, cancelAnimationFrame, ResizeObserver.disconnect); reactivity reads inputs synchronously. One self-caught nit (Möbius f' sign, AA-only) fixed in commit 2.

Adversarial Review (Codex, cross-model)

Codex flagged 2 × P2 (no P1):

  • Reset button stayed disabled on param-only edits → fixed (playgroundDirty() now includes param drift). Verified live.
  • WebGL2 init failure left the stage blank → fixed (glInitFailed flips to the CPU path).

Verification (live, via headless browser)

No console errors across: Escher zᵃ (spiral), 1/z (inversion), Möbius (handles + correct formula), sin(1/z) (essential-singularity kaleidoscope), drag→c updating the formula, mirror fill, reset enabling after a param edit, dragging the Möbius zero. Mobile (390×844) layout verified — control strip wraps, tool rail becomes a bottom bar.

Plan Completion

All shaping slices V1–V5 landed (see shaping/complex-playground-shaping.md). Conformal coordinate grid was intentionally dropped (clutter vs. the image warp itself); origin cross + unit circle kept.

Notes

  • This repo has no VERSION/CHANGELOG.md, so no version bump (consistent with prior PRs).
  • README still says "Two views" and lists some deleted components — pre-existing staleness, left out of scope here.

Test plan

  • npm run test — 44 passing
  • npm run check — 0 errors
  • npm run build — clean
  • Live QA, desktop + mobile, no console errors

🤖 Generated with Claude Code


Staging: https://silvio-tententoon-complex-playground.pgs.sh/ — open the app, then click the 5th tool-rail button (graph glyph) to enter the complex playground.

silviot and others added 3 commits May 30, 2026 23:29
A new "playground" view (5th tool-rail button) that warps the loaded
image (gallery picture, bundled sample, or grid/polar pattern) through a
chosen complex function f(z), GeoGebra-style:

- Curated preset shelf: identity, z², zⁿ, 1/z, Möbius, Joukowski, exp,
  log, Escher zᵃ, sin. One GLSL branch each (uber-shader), mirrored on
  CPU for the no-WebGL2 fallback. Per-preset analytic f' drives mip-LOD
  anti-aliasing.
- Live, schema-generated controls (sliders / complex number fields) +
  reset; the active formula is rendered live and updates as you tweak.
- Hand-drag adds a complex constant c to the formula, with a toggle for
  domain f(z+c) vs output f(z)+c composition; wheel zooms.
- Draggable on-canvas handles for a preset's zero/pole (Möbius), plus an
  origin cross and unit-circle overlay.
- Fill modes (tile / clamp / mirror) so out-of-image samples never go
  black.

Its own light complex frame (origin + scale), independent of the Droste
doc.rect; reuses doc.image and the existing image-source paths. Verified
live (no console errors); 18 unit tests cover the preset math + formula
text. Shaping doc: shaping/complex-playground-shaping.md.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Two more "cool" presets: tan(z) (periodic, poles) and sin(1/z) (essential
  singularity — dense kaleidoscope at the origin). Shader gains an explicit
  fallback branch.
- Fix the Möbius derivative sign: f'(z) = k(z0−z∞)/(z−z∞)². Only fed the AA
  footprint (|f'|), so no visible change, but it was wrong. Locked by a test.

Verified live (sin(1/z) renders, no console errors); 22 preset tests (44 total).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- playgroundDirty() now also returns true when a preset parameter differs
  from its default (a slider nudge or dragged Möbius zero/pole), so the
  reset button enables on param-only edits — not just pan/zoom. Verified live.
- PlaygroundStage falls back to the CPU path when WebGL2 init throws after
  detectCapabilities reported it available (glInitFailed flag), instead of the
  render guard returning forever and leaving the stage blank.

Both P2 findings from codex review. Tests/typecheck/build green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@silviot silviot merged commit 3dd69cf into main Jun 2, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant